package com.c2soft.ncmxTrade.controller;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import javax.annotation.PostConstruct;

import lombok.extern.log4j.Log4j2;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.c2soft.ncmxTrade.domain.Quote;
@Log4j2
@Controller
public class QuoteWebSocketController {

	@Autowired
	private SimpMessagingTemplate template;

	private TaskScheduler scheduler = new ConcurrentTaskScheduler();
	
	private List<Quote> quotes = new ArrayList<Quote>();

	private enum Symbols {
		GOLD_L, SILVER_L,ZINC_L,COPPER_L,COPPER_S;
		
		private static final List<Symbols> VALUES = Collections
				.unmodifiableList(Arrays.asList(values()));
		
		private static final int SIZE = VALUES.size();
		
		private static final Random RANDOM = new Random();

		public static Symbols randomSymbol() {
			return VALUES.get(RANDOM.nextInt(SIZE));
		}	
	};
	
	private String getRandomDoubleInRange(double min,double max){
		double random = new Random().nextDouble();
		double result = min + (random * (max - min));
		return String.valueOf(result);
	}
	
	private String getRandomIntInRange(int min,int max){
		int random = new Random().nextInt();
		int result = min + (random * (max - min));
		return String.valueOf(result);
	}

	/**
	 * Iterates stock list, update the price by randomly choosing a positive or
	 * negative percentage, then broadcast it to all subscribing clients
	 */
	private void updatePriceAndBroadcast() {
		if(CollectionUtils.isEmpty(quotes)){
			quotes.add(getAnyRandomQuoteForSymbol(Symbols.COPPER_S.toString()));
			quotes.add(getAnyRandomQuoteForSymbol(Symbols.COPPER_L.toString()));
			quotes.add(getAnyRandomQuoteForSymbol(Symbols.ZINC_L.toString()));
			quotes.add(getAnyRandomQuoteForSymbol(Symbols.SILVER_L.toString()));
			quotes.add(getAnyRandomQuoteForSymbol(Symbols.GOLD_L.toString()));
		}
		int i = 0;
		for (Quote quote : quotes) {
			
			quote = getAnyRandomQuoteForSymbol(quote.getSymbol());

			quotes.set(i, quote);
			i++;
		}
		template.convertAndSend("/topic/quote", quotes);
	}

	/**
	 * Invoked after bean creation is complete, this method will schedule
	 * updatePriceAndBroacast every 1 second
	 */
	@PostConstruct
	private void broadcastTimePeriodically() {
		scheduler.scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				updatePriceAndBroadcast();
			}
		}, 1000);
	}
	
	

	/**
	 * Handler to add one stock
	 */
	@MessageMapping("/addStock")
	public void addStock() throws Exception {

		quotes.add(getAnyRandomQuote());
		updatePriceAndBroadcast();
	}

	/**
	 * Handler to remove all stocks
	 */
	@MessageMapping("/removeAllStocks")
	public void removeAllStocks() {
		quotes.clear();
		updatePriceAndBroadcast();
	}

	/**
	 * Serve the main page
	 */
	@RequestMapping(value = "/quoteWebSocket", method = RequestMethod.GET)
	public String quoteWebSckt() {

		return "quoteWebSckt";
	}
	
	
	private Quote getAnyRandomQuote(){
		String l_otype = "RL";
		String l_price = getRandomDoubleInRange(100,1000);
		String l_ptype = "Intra";
		String l_ql = getRandomIntInRange(1,10);
		String l_qt = getRandomIntInRange(1,20);
		String l_qw = getRandomIntInRange(1,10);
		String l_symbol = Symbols.randomSymbol().toString();
		String l_tp = getRandomDoubleInRange(100,1000);
		String l_insname = getRandomIntInRange(1111,99999);
		
		return Quote.builder().insname(l_insname).otype(l_otype)
				.price(l_price).ptype(l_ptype).ql(l_ql).qt(l_qt).qw(l_qw)
				.symbol(l_symbol).tp(l_tp).build();
	}
	
	private Quote getAnyRandomQuoteForSymbol(String symbol){
		String l_otype = "RL";
		String l_price = getRandomDoubleInRange(100,1000);
		String l_ptype = "Intra";
		String l_ql = getRandomIntInRange(1,10);
		String l_qt = getRandomIntInRange(1,20);
		String l_qw = getRandomIntInRange(1,10);
		String l_symbol = symbol;
		String l_tp = getRandomDoubleInRange(100,1000);
		String l_insname = getRandomIntInRange(1111,99999);
		
		return Quote.builder().insname(l_insname).otype(l_otype)
				.price(l_price).ptype(l_ptype).ql(l_ql).qt(l_qt).qw(l_qw)
				.symbol(l_symbol).tp(l_tp).build();
	}
	
}
